package expression;

import java.util.ArrayList;
import java.util.List;

import choco.integer.IntDomainVar;
import choco.integer.IntExp;

import common.MCore;

import constraint.MPredicate;

public abstract class MIntVar extends MIntExpr {
	public static int MAX_VALUE = 1000000;
	public static int MIN_VALUE = -1000000;
	public static int MAX_CARD = 1000;
	public static int MAX_ENUM = 100;
	
	protected String name;
	protected IntDomainVar variable;
	protected List<MPredicate> predicates;
	protected List<MIntVar> varDependencies;
	protected List<MPredicate> predDependencies;

	public MIntVar(MCore c, String n) {
		super(c);
		c.getVariables().add(this);

		name = n;
		
		predicates = new ArrayList<MPredicate>();
		varDependencies = new ArrayList<MIntVar>();
		predDependencies = new ArrayList<MPredicate>();
	}
	
	public String getName() {
		return name;
	}

	public IntDomainVar getVariable() {
		return variable;
	}

	public List<MPredicate> getPredicates() {
		return predicates;
	}
	
	public List<MIntVar> getVarDepencies() {
		return varDependencies;
	}
	
	public List<MPredicate> getPredDepencies() {
		return predDependencies;
	}
	
	public void addPredicate(MPredicate p) {
		if (!predicates.contains(p))
			predicates.add(p);
	}
	
	protected void initPredDep() {
		// predDependencies
		List<MPredicate> newPred = new ArrayList<MPredicate>();
		newPred.addAll(getPredicates());
		
		while (newPred.size() > 0) {
			MPredicate pred = newPred.get(0);
			newPred.remove(0);
			predDependencies.add(pred);
			
			for (MIntVar v: pred.getVariables()) {
				for (MPredicate p: v.getPredicates()) {
					if ((p != pred) && (!newPred.contains(p)) && (!predDependencies.contains(p))) {
						newPred.add(p);
					}
				}
			}
		}		
	}
	
	protected void initVarDep() {
		// varDpendencies
		for (MPredicate p: predDependencies) {
			for (MIntVar v: p.getVariables()) {
				if ((v != this) && (!varDependencies.contains(v))) {
					varDependencies.add(v);
				}
			}
		}		
	}
	
	public void init() {
		initPredDep();
		initVarDep();
	}
	
	public abstract void reset();
	
	public String toText() {
		return name;
	}
	
	public List<MIntVar> getVariables() {
		List<MIntVar> vars = new ArrayList<MIntVar>();
		vars.add(this);
		
		return vars;
	}
	
	public IntExp intExp() {
		return variable;
	}	
}
